/**
 * @author Jason Pratt
 */

package edu.cmu.cs.stage3.alice.authoringtool.util;

import edu.cmu.cs.stage3.resourceBundle.I18n;

import edu.cmu.cs.stage3.alice.authoringtool.AuthoringTool;
import edu.cmu.cs.stage3.alice.authoringtool.AuthoringToolResources;
import edu.cmu.cs.stage3.alice.authoringtool.dialog.DeleteContentPane;
import edu.cmu.cs.stage3.alice.core.Property;
import edu.cmu.cs.stage3.alice.core.reference.PropertyReference;
import edu.cmu.cs.stage3.util.Criterion;
import edu.cmu.cs.stage3.util.HowMuch;
import edu.cmu.cs.stage3.util.StringObjectPair;

public class ElementPopupUtilities {

 protected static Class[] elementPopupRunnableParams = new Class[] { edu.cmu.cs.stage3.alice.core.Element.class };

 public static void createAndShowElementPopupMenu (edu.cmu.cs.stage3.alice.core.Element element, java.util.Vector structure, java.awt.Component component, int x, int y) {
  javax.swing.JPopupMenu popup = makeElementPopupMenu( element, structure );
  popup.show( component, x, y );
  PopupMenuUtilities.ensurePopupIsOnScreen( popup );
  }

 /**
  * @deprecated use makeElementPopupMenu
  */
 //Rem @Deprecated
 public static javax.swing.JPopupMenu makeElementPopup (edu.cmu.cs.stage3.alice.core.Element element, java.util.Vector structure) {
  return makeElementPopupMenu( element, structure );
  }
 public static javax.swing.JPopupMenu makeElementPopupMenu (edu.cmu.cs.stage3.alice.core.Element element, java.util.Vector structure) {
  if ((element != null) && (structure != null)) {
   Object[] initArgs = new Object[] { element };
   substituteRunnables( initArgs, structure );
   return PopupMenuUtilities.makePopupMenu( structure );
  } else {
   return null;
   }
  }

 public static void substituteRunnables (Object[] initArgs, java.util.Vector structure) {
  for (java.util.ListIterator iter = structure.listIterator(); iter.hasNext();) {
   String error = null; //L
   Object o = iter.next();
   if (o instanceof Class && ElementPopupRunnable.class.isAssignableFrom( (Class)o )) {
    try {
     //L para tentar funcionar 'copiar/colar', ainda sobra erro
     //L at edu.cmu.cs.stage3.alice.core.CopyFactory$ElementCapsule.manufacture(CopyFactory.java:290)'
     //L ...
     //L at edu.cmu.cs.stage3.alice.core.Element.HACK_createCopy(Element.java:1054) - edu.cmu.cs.stage3.alice.core.ExceptionWrapper: UnresolvablePropertyReferencesException
     //L at edu.cmu.cs.stage3.alice.authoringtool.util.ElementPopupUtilities$MakeCopyRunnable.run(ElementPopupUtilities.java:368)
     ElementPopupRunnable r = null; //L
     r = (ElementPopupRunnable)((Class)o).getConstructor( elementPopupRunnableParams ).newInstance( initArgs ); //L
     StringObjectPair newPair = new StringObjectPair( r.getDefaultLabel(), r );
     iter.set( newPair );
    } catch (NoSuchMethodException e) {
     AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e ); error = e.toString(); //L
    } catch (IllegalAccessException e) {
     AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e ); error = e.toString(); //L
    } catch (InstantiationException e) {
     AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e ); error = e.toString(); //L
    } catch (java.lang.reflect.InvocationTargetException e) {
     AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e ); error = e.toString(); //L
    } catch (Exception e) {
     AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e ); error = " #initArgs="+initArgs.length+": "+e.toString(); //L
     }
    if (error != null) System.err.println("ElementPopupUtilities.java: substituteRunnables(...): "+edu.cmu.cs.stage3.util.StrUtilities.getComponentName(o)+": "+error); //L
   } else if (o instanceof ElementPopupRunnable) {
    ElementPopupRunnable r = (ElementPopupRunnable)o;
    StringObjectPair newPair = new StringObjectPair( r.getDefaultLabel(), r );
    iter.set( newPair );
   } else if (o instanceof StringObjectPair) {
    StringObjectPair pair = (StringObjectPair)o;
    if ((pair.getObject() instanceof Class) && ElementPopupRunnable.class.isAssignableFrom( (Class)pair.getObject() )) {
     try {
      StringObjectPair newPair = new StringObjectPair( pair.getString(), ((Class)pair.getObject()).getConstructor( elementPopupRunnableParams ).newInstance( initArgs ) );
      iter.set( newPair );
      //      pair.setObject( ((Class)pair.getObject()).getConstructor( elementPopupRunnableParams ).newInstance( initArgs ) );
     } catch (NoSuchMethodException e) {
      AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e );
     } catch (IllegalAccessException e) {
      AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e );
     } catch (InstantiationException e) {
      AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e );
     } catch (java.lang.reflect.InvocationTargetException e) {
      AuthoringTool.getInstance().showErrorDialog( "Error building popup.", e );
     }
    } else if (pair.getObject() instanceof java.util.Vector) {
     substituteRunnables( initArgs, (java.util.Vector)pair.getObject() );
     }
    }
   }
  } // public static void substituteRunnables(Object[] initArgs, java.util.Vector structure)

 // Called by: 2 'getDefaultQuestionStructure (edu.cmu.cs.stage3.alice.core.Question)'
 public static java.util.Vector makeCoerceToStructure (final edu.cmu.cs.stage3.alice.core.Element element) {
  if ((element != null) && element.isCoercionSupported()) {
   java.util.Vector structure = new java.util.Vector();
   java.util.Vector subStructure = new java.util.Vector();

   Class[] classes = element.getSupportedCoercionClasses();
   if (classes != null) {
    //LOB for (final Class c : classes)
    int t_tam = classes!=null ? classes.length : 0;
    for (int i_i=0; i_i<t_tam; i_i++) {
     final Class c = classes[i_i];
     String repr = AuthoringToolResources.getReprForValue( c );
     Runnable runnable = new Runnable() {
      public void run () {
       AuthoringTool.getInstance().getUndoRedoStack().startCompound();
       element.coerceTo( c );
       AuthoringTool.getInstance().getUndoRedoStack().stopCompound();
       }
      };
     subStructure.add( new StringObjectPair( repr, runnable ) );
     }
    if (subStructure.size() > 0){
     structure.add( new StringObjectPair( "change to", subStructure ) ); // change to
     return structure;
     }
    else {
     return null;
     }
    }
   }
  return null;
  }

 public static java.util.Vector getDefaultStructure (edu.cmu.cs.stage3.alice.core.Element element) {
  return getDefaultStructure( element, true, null, null, null );
  }

 public static java.util.Vector getDefaultStructure (edu.cmu.cs.stage3.alice.core.Element element, boolean elementEnabled, AuthoringTool authoringTool, javax.swing.JTree jtree, javax.swing.tree.TreePath treePath) {
  if (element instanceof edu.cmu.cs.stage3.alice.core.Response) {
   return getDefaultResponseStructure( (edu.cmu.cs.stage3.alice.core.Response)element );
  } else if (element instanceof edu.cmu.cs.stage3.alice.core.Question) {
   return getDefaultQuestionStructure( (edu.cmu.cs.stage3.alice.core.Question)element );
  } else if (AuthoringToolResources.characterCriterion.accept( element )) {
   return getDefaultCharacterStructure( element, elementEnabled, authoringTool, jtree, treePath );
  } else if (element instanceof edu.cmu.cs.stage3.alice.core.World) {
   return getDefaultWorldStructure( (edu.cmu.cs.stage3.alice.core.World)element );
  } else {
   return getDefaultElementStructure( element, jtree, treePath );
   }
  }

 public static java.util.Vector getDefaultCharacterStructure (edu.cmu.cs.stage3.alice.core.Element element, boolean elementEnabled, AuthoringTool authoringTool, javax.swing.JTree jtree, javax.swing.tree.TreePath treePath) {
  java.util.Vector popupStructure = new java.util.Vector();
  popupStructure.add( new StringObjectPair( AuthoringToolResources.getReprForValue( element ), null ) );
  popupStructure.add( new StringObjectPair( "separator", javax.swing.JSeparator.class ) );
  if (elementEnabled) {
   popupStructure.add( new StringObjectPair( "methods", edu.cmu.cs.stage3.alice.authoringtool.util.PopupMenuUtilities.makeDefaultOneShotStructure( element ) ) );
   }
  if ((jtree != null) && (treePath != null)) {
   Runnable renameRunnable = new RenameRunnable( element, jtree, treePath );
   popupStructure.add( renameRunnable );
   }

  if (AuthoringToolResources.characterCriterion.accept( element )) {
   popupStructure.add( DeleteRunnable.class );
   popupStructure.add( SaveCharacterRunnable.class );
   }
  else {
   popupStructure.add( DeleteRunnable.class );
   }

  return popupStructure;
  }

 public static java.util.Vector getDefaultWorldStructure (edu.cmu.cs.stage3.alice.core.World world) {
  java.util.Vector popupStructure =  new java.util.Vector();
  return popupStructure;
  }

 public static java.util.Vector getDefaultResponseStructure (edu.cmu.cs.stage3.alice.core.Response response) {
  java.util.Vector structure =  new java.util.Vector();
  structure.add( MakeCopyRunnable.class );
  structure.add( DeleteRunnable.class );
  structure.add( ToggleCommentingRunnable.class );
  java.util.Vector coerceToStructure = makeCoerceToStructure( response );
  if (coerceToStructure != null) {
   structure.addAll( coerceToStructure );
   }
  return structure;
  }

 public static java.util.Vector getDefaultQuestionStructure (edu.cmu.cs.stage3.alice.core.Question question) {
  java.util.Vector structure =  new java.util.Vector();
  structure.add( MakeCopyRunnable.class );
  structure.add( DeleteRunnable.class );
  // structure.add( ToggleCommentingRunnable.class );
  java.util.Vector coerceToStructure = makeCoerceToStructure( question );
  if (coerceToStructure != null) {
   structure.addAll( coerceToStructure );
   }
  return structure;
  }

 public static java.util.Vector getDefaultElementStructure( edu.cmu.cs.stage3.alice.core.Element element, javax.swing.JTree jtree, javax.swing.tree.TreePath treePath) {
  java.util.Vector structure =  new java.util.Vector();
  if ((jtree != null) && (treePath != null)) {
   Runnable renameRunnable = new RenameRunnable( element, jtree, treePath );
   structure.add( renameRunnable );
   }
  structure.add( DeleteRunnable.class );

  return structure;
  }

 public static abstract class ElementPopupRunnable implements Runnable {
  protected edu.cmu.cs.stage3.alice.core.Element element;

  protected ElementPopupRunnable (edu.cmu.cs.stage3.alice.core.Element element) {
   this.element = element;
   }

  public edu.cmu.cs.stage3.alice.core.Element getElement () {
   return element;
   }

  public abstract String getDefaultLabel ();
  }

 //TODO: there are issues with Models whose world and scenegraph trees don't match
 public static class DeleteRunnable extends ElementPopupRunnable {
  public final static Criterion namedHeadCriterion = new Criterion() {
   public boolean accept (Object o) {
    if (o instanceof edu.cmu.cs.stage3.alice.core.Transformable) {
     if ("head".equalsIgnoreCase( ((edu.cmu.cs.stage3.alice.core.Transformable)o).name.getStringValue() )) {
      return true;
      }
     }
    return false;
    }
   };
  protected AuthoringTool authoringTool;

  public DeleteRunnable (edu.cmu.cs.stage3.alice.core.Element element) { //L , AuthoringTool authoringTool)
   super( element );
   this.authoringTool = AuthoringTool.getInstance(); //L authoringTool;
   }

  //Rem @Override
  public String getDefaultLabel () {
   return I18n.getString("msg_del"); // "delete"
   }

  public void run () {
   PropertyReference[] references = element.getRoot().getPropertyReferencesTo( element, HowMuch.INSTANCE_AND_ALL_DESCENDANTS, true, true );
   // System.out.println("ElementPopupUtilities.java: run()");
   //System.out.println("TrashComponent.java: drop(java.awt.dnd.DropTargetDropEvent): "+edu.cmu.cs.stage3.util.StrUtilities.getComponentName(ElementReferenceTransferable.elementReferenceFlavor));
   if (references.length > 0) {
    AuthoringToolResources.garbageCollectIfPossible( references );
    references = element.getRoot().getPropertyReferencesTo( element, HowMuch.INSTANCE_AND_ALL_DESCENDANTS, true, true );
    }
   if (references.length > 0) {
    //LOB for (PropertyReference reference : references)
    int t_tam = references!=null ? references.length : 0;
    for (int i_i=0; i_i<t_tam; i_i++) {
     edu.cmu.cs.stage3.alice.core.Element refReferenceI = references[i_i].getReference(); //L reference.getReference();
     edu.cmu.cs.stage3.alice.core.Property refPropertyI = references[i_i].getProperty(); //L reference.getProperty();
     edu.cmu.cs.stage3.alice.core.Element refOwnerI = refPropertyI.getOwner();
     if (references[i_i].getProperty().isAlsoKnownAs( edu.cmu.cs.stage3.alice.core.Model.class, "geometry" )) { //L if (reference.getProperty()... )
      if (refOwnerI instanceof edu.cmu.cs.stage3.alice.core.Model) { refReferenceI.setParent( refOwnerI ); }
      }
     }
    references = element.getRoot().getPropertyReferencesTo( element, HowMuch.INSTANCE_AND_ALL_DESCENDANTS, true, true );
    }
   if (references.length > 0) {
    DeleteContentPane.showDeleteDialog( this, authoringTool );
   } else {
    AuthoringTool.getInstance().getUndoRedoStack().startCompound();
    if (element instanceof edu.cmu.cs.stage3.alice.core.Transformable) {
     if (element instanceof edu.cmu.cs.stage3.alice.core.Model) { }
     }
    edu.cmu.cs.stage3.alice.core.Element parent = element.getParent();
    if (parent != null) {
     //is this too liberal?
     edu.cmu.cs.stage3.alice.core.Property[] properties = parent.getProperties();
     //LOB for (Property propertie : properties)
     int t_tam = properties!=null ? properties.length : 0;
     Property propertie = null; //L
     for (int i_i=0; i_i<t_tam; i_i++) {
      propertie = properties[i_i]; //L
      if (propertie.get() == element) { //L if (propertie.get() == element )
       propertie.set( AuthoringToolResources.getDefaultValueForClass( propertie.getValueClass() ) );
      } else if (propertie instanceof edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty) {
       edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty oap = (edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty)propertie;
//System.out.println("ElementPopupUtilities.java: run(): "+i_i+": "+propertie+" oap.size="+oap.size());// if (i_i==3)
       int j=0;
       while (j<oap.size()) { // find the position of the 'element' in 'edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty'
        if (oap.get( j ) == element) {
//System.out.println("ElementPopupUtilities.java: run(): "+i_i+": remove "+propertie);
         oap.remove( j ); // edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty.remove(j)
        } else {
         j++;
         }
        }
       }
      }
     // element.removeFromParent();
     parent.removeChild( element ); // aqui
     }

    AuthoringTool.getInstance().getUndoRedoStack().stopCompound();
    }
   } // public void run()

  } // public static class DeleteRunnable extends ElementPopupRunnable

 public static class RenameRunnable extends ElementPopupRunnable {
  private javax.swing.JTree jtree;
  private javax.swing.tree.TreePath treePath;

  public RenameRunnable (edu.cmu.cs.stage3.alice.core.Element element, javax.swing.JTree jtree, javax.swing.tree.TreePath treePath) {
   super( element );
   this.jtree = jtree;
   this.treePath = treePath;
   }

  //Rem @Override
  public String getDefaultLabel () {
   return I18n.getString("msg_rename"); // "rename"
   }

  public void run () {
   jtree.startEditingAtPath( treePath );
   }
  } // public static class RenameRunnable extends ElementPopupRunnable

 public static class MakeCopyRunnable extends ElementPopupRunnable {
  public MakeCopyRunnable (edu.cmu.cs.stage3.alice.core.Element element) {
   super( element );
   }

  //Rem @Override
  public String getDefaultLabel () {
   return I18n.getString("epu_makeCopy"); // "make copy"
   }

  public void run () {
   AuthoringTool.getInstance().getUndoRedoStack().startCompound();

   String name = AuthoringToolResources.getNameForNewChild( element.name.getStringValue(), element.getParent() );

   // should createCopyNamed handle this?
   if (element.getParent() instanceof edu.cmu.cs.stage3.alice.core.response.CompositeResponse) {
    int index = ((edu.cmu.cs.stage3.alice.core.response.CompositeResponse)element.getParent()).componentResponses.indexOf( element );
    edu.cmu.cs.stage3.alice.core.Element copy = element.HACK_createCopy( name, element.getParent(), index + 1, null, null );
    ((edu.cmu.cs.stage3.alice.core.response.CompositeResponse)element.getParent()).componentResponses.add(index+1, copy);
   } else if (element.getParent() instanceof edu.cmu.cs.stage3.alice.core.question.userdefined.Composite) {
    int index = ((edu.cmu.cs.stage3.alice.core.question.userdefined.Composite)element.getParent()).components.indexOf( element );
    edu.cmu.cs.stage3.alice.core.Element copy = element.HACK_createCopy( name, element.getParent(), index + 1, null, null );
    ((edu.cmu.cs.stage3.alice.core.question.userdefined.Composite)element.getParent()).components.add(index+1, copy);
   } else {
    edu.cmu.cs.stage3.alice.core.Element copy = element.createCopyNamed( name );
    AuthoringToolResources.addElementToAppropriateProperty( copy, copy.getParent() );
   }

   AuthoringTool.getInstance().getUndoRedoStack().stopCompound();
  }
 }

 public static class SaveCharacterRunnable extends ElementPopupRunnable {
  protected AuthoringTool authoringTool;

  public SaveCharacterRunnable( edu.cmu.cs.stage3.alice.core.Element element, AuthoringTool authoringTool) {
   super( element );
   this.authoringTool = authoringTool;
   }

  //Rem @Override
  public String getDefaultLabel () {
   return I18n.getString("epu_saveObj"); // "save object..."
   }

  public void run () {
  }
 }

 // Called by: edu.cmu.cs.stage3.alice.authoringtool.util.CustomMouseAdapter.mousePressed ->...-> edu.cmu.cs.stage3.alice.authoringtool.util.ElementPopupUtilities.substituteRunnables: new Instace()
 public static class ToggleCommentingRunnable extends ElementPopupRunnable {
  public ToggleCommentingRunnable (edu.cmu.cs.stage3.alice.core.Element element) {
   super( element );
   //T System.out.println("\n\nElementPopupUtilities.java: ToggleCommentingRunnable: "+element);
   //T try{String _str=""; System.out.println(_str.charAt(3));}catch(Exception e) {e.printStackTrace();}
   if (! (element instanceof edu.cmu.cs.stage3.alice.core.Code)) {
    throw new IllegalArgumentException( "ToggleCommentRunnable only accepts Responses or User-Defined Questions; found: " + element );
    }
   }

  //Rem @Override
  public String getDefaultLabel () {
   return I18n.getString("epu_disable"); // "disable"
   }

  public void run () {
  }
 }

 public static class SetElementScopeRunnable extends ElementPopupRunnable {
  private AuthoringTool authoringTool;

  public SetElementScopeRunnable( edu.cmu.cs.stage3.alice.core.Element element, AuthoringTool authoringTool) {
   super( element );
   this.authoringTool = authoringTool;
   }

  //Rem @Override
  public String getDefaultLabel () {
   return I18n.getString("epu_switchScope"); // "switch to this element's scope"
   }

  public void run() {
   authoringTool.setElementScope( element );
  }
 }

 public static class SortGroupAlphabeticallyRunnable extends ElementPopupRunnable {
  protected java.util.Comparator sorter = new java.util.Comparator() {
   public int compare( Object o1, Object o2) {
    if ((o1 instanceof edu.cmu.cs.stage3.alice.core.Element) && (o2 instanceof edu.cmu.cs.stage3.alice.core.Element)) {
     String name1 = ((edu.cmu.cs.stage3.alice.core.Element)o1).name.getStringValue();
     String name2 = ((edu.cmu.cs.stage3.alice.core.Element)o2).name.getStringValue();
     return name1.compareTo( name2 );
    } else {
     return 0;
     }
    }
   };

  public SortGroupAlphabeticallyRunnable (edu.cmu.cs.stage3.alice.core.Element element) {
   super( element );
   }

  //Rem @Override
  public String getDefaultLabel () {
   return I18n.getString("epu_sort"); // "sort alphabetically"
   }

  public void run () {
   // TODO Auto-generated method stub
   }

  }

 }
